//@author A0105543N
#include "Record.h"

Record::Record()
{
	xpensTrace = new Trace;
	ExpCategory.push_back("");
	ExpCategory.push_back("Food");
	ExpCategory.push_back("Clothes"); 
	ExpCategory.push_back("Transportation");
	ExpCategory.push_back("Accomadation");
	ExpCategory.push_back("Entertainment");
	ExpCategory.push_back("Education");
	ExpCategory.push_back("Investment");
	ExpCategory.push_back("Telecommunication");
	otherExp = 9;
	PayCategory.push_back("");
	PayCategory.push_back("Salary");
	PayCategory.push_back("Insurance");
	PayCategory.push_back("Investment");
	otherPay = 4;
}

Trace* Record::getTrace()
{
	return xpensTrace;
}

bool Record::newRecord(Item& newItem)
{
	if (!newItem.record()) return false;
	if (!recordCategory(newItem)) return false;
	return true;
}
bool Record::updateRecord(streampos address, Item& newItem)
{
	if (newItem.isexpense()) {
		ifstream infile("Expense.txt");
		newItem.record_from_file(infile, address);
		infile.close();
	}
	else {
		ifstream infile("Payment.txt");
		newItem.record_from_file(infile,address);
		infile.close();
	}
	string tempString;
	while (true){
		cout << "\nWhich attribute do you want to update?\n";
		cout << "1. Name\n2. Price\n3. Date\n4. Category\n";
		if (newItem.isexpense()) cout << "5. Venue\n";
		else cout << "5. Payer\n";
		cout << "6. Exit\n";
		getline(cin,tempString);
		if (tempString == "" || tempString == "\n")
			getline(cin,tempString);
		if (tempString == "6") return true;
		while (tempString.length() != 1 || (tempString[0] - '0' > 5 || tempString[0] - '0' < 1)) {
			cout << "Invalid attribute ID. Input 0 to exit.\n";
			getline(cin,tempString);
			if (tempString.length() == 1 && tempString == "0") return false;
		}
		int command = tempString[0] - '0';
		switch (command){
		case 1: if (!newItem.recordName()) return false;
			break;
		case 2: if (!newItem.recordPrice()) return false;
			break;
		case 3: if (!newItem.recordDate()) return false;
			break;
		case 4: if (!recordCategory(newItem)) return false;
			break;
		case 5: if (!newItem.recordExtra()) return false;
			break;
		default: return false;
		}
	}
	return true;
}
bool Record::createItem(Item& newItem)
{
	if (!newRecord(newItem)) return false;
	if (newItem.isexpense()) {
		newItem.writefile("Expense.txt");}//store it into text file for successful recording
	else newItem.writefile("Payment.txt");
	xpensTrace -> addTrace(newItem);   //update total expense or payment
	return true;
};

bool Record::recordCategory(Item& newItem)
{
	int cat;
	if (newItem.isexpense()) {
			display(ExpCategory);

			cout << "Category:\n";
			cin >> cat;{
			
			if ( cat > otherExp || cat < 1) {cout << "Invalid category input.\n" ; return false;}
			
			if (cat == otherExp){
				cout << "What Category?" << endl; 
				string newcat;
				getline(cin,newcat);
				getline(cin,newcat);
				while (newcat.find(' ',0) != string::npos || newcat.length() > 20) {  //check validity
					cout << "Category can not contain white space and the length should not exceed 20. Input again. Press Enter key to exit.\n"; 
					getline(cin,newcat);
					if (newcat == "\n") return false;}
				ExpCategory.push_back(newcat);
				otherExp ++;}//update number of categories
			newItem.setCategory(ExpCategory[cat]);
			}
		}

		else {
			display(PayCategory);//similar to expense category operation
			
			cout << "Category:\n";
			cin >> cat;{
			if (cat > otherPay || cat < 1) {
				cout << "Invalid category input.\n"; return false; }
			if (cat == otherPay){
				cout << "What Category?" << endl; 
				string newcat;
				getline(cin,newcat);
				getline(cin,newcat);
				while (newcat.find(' ',0) != string::npos) {
					cout << "Category can not contain white space and the length should not exceed 20. Input again. Press Enter key to exit.\n"; 
					getline(cin,newcat);
					if (newcat == "\n") return false;}
				PayCategory.push_back(newcat);
				otherPay ++;}
			newItem.setCategory(PayCategory[cat]);
			}
		}
		return true;
}
void Record::display(vector<string> CategoryList)
{
	vector <string>::iterator myIter;
	int i = 1;

	cout << "Category" << endl;
	for (myIter = CategoryList. begin() + 1; myIter != CategoryList. end(); myIter ++, i++)
	{
		cout << i << ": " << *myIter << endl;
	}
	cout << i << ": other" << endl;
}

bool Record::deleteExp(int& deleteID,string& category)
{
	display(ExpCategory);
	cout << "Which category do you want to delete? \n";
	cin >> deleteID;
	if (deleteID <  1 || deleteID >= otherExp){//always check! defensive coding
		cout << "Invalid category ID\n";
		return false;
	}
	category = ExpCategory[deleteID];         //need to remember category in trash in preparation for undo
	deleteExpCat(deleteID);
	return true;
}

bool Record::deletePay(int& deleteID, string& category)
{
	display(PayCategory);
	cout << "Which category do you want to delete? \n";
	cin >>deleteID;
	if (deleteID < 1 || deleteID >= otherPay){
		cout << "Invalid category ID\n";
		return false;
	}
	category = PayCategory[deleteID];
	deletePayCat(deleteID);
	return true;
}

void Record::deleteExpCat(int deleteID)
{
	vector<string>::iterator myIter;
	myIter = ExpCategory.begin() + deleteID;
	ExpCategory.erase(myIter);
	otherExp --;
}

void Record::deletePayCat(int deleteID)
{
	vector<string>::iterator myIter;
	myIter = PayCategory.begin() + deleteID;
	PayCategory.erase(myIter);
	otherPay --;
}

void Record::addExpCat(int ID, string category)
{
	vector<string>::iterator myIter;
	myIter = ExpCategory.begin() + ID;
	ExpCategory.insert(myIter,category);
	otherExp ++;
}

void Record::addPayCat(int ID, string category)
{
	vector<string>::iterator myIter;
	myIter = PayCategory.begin() + ID;
	PayCategory.insert(myIter,category);
	otherExp ++;
}

bool Record::updateItem( streamoff address, Item& newItem )
{	
	if (!newItem.checkEmpty()) xpensTrace -> addTrace( newItem );

	char* filename;
	if (newItem.isexpense()) {
		filename = "Expense.txt";}
	else {
		filename = "Payment.txt";}
	
	ifstream infile(filename);                 //move everything to temp.txt first
	string buffer;
	ofstream newStorage("temp.txt");
	
	streampos endpos;
	infile.seekg(0,ios::end);
	endpos = infile.tellg();

	infile.seekg(ios::beg);

	char c;

	while ( address > infile.tellg() ){
		infile.get(c);
		newStorage.put(c);
	}
	newStorage.flush();
	if (newItem.isexpense()) {
		XpensItem tempItem;
		tempItem.record_from_file(infile, infile.tellg());
		}
	else {
		PaymentItem tempItem;
		tempItem.record_from_file(infile, infile.tellg());}

	if (!newItem.checkEmpty()) {      //write the new item to temp.txt
		newItem.writefile("temp.txt");
	}
	newStorage.flush();
	newStorage.close();

	ofstream tempStorage("temp.txt",ios::app);
	while ( !infile.eof()  && infile.tellg() < endpos ){
		infile.get(c);
		tempStorage.put(c);
	}
	infile.close();
	tempStorage.flush();
	tempStorage.close();
	ifstream newinfile ("temp.txt");             //move everything back to the original file
	ofstream outfile(filename);
	infile.seekg(ios::beg);
	
	while( newinfile.get(c) ){
		outfile.put(c);
	}
	outfile.flush();
	newinfile.close();
	outfile.close();
	return true;
}

void Record::setCategory()
{
	ifstream infile("Figure.txt");
	string category;
	PayCategory.clear();
	ExpCategory.clear();
	otherPay = 1;
	otherExp = 1;

	PayCategory.push_back("");
	ExpCategory.push_back("");

	double dummy;
	infile >> dummy;
	infile >> dummy;
	if (infile >> category)
	{
	while (category != "_")
	{
		ExpCategory.push_back(category);
		infile >> category;
		otherExp ++;
	}

	while (infile >> category)
	{
		PayCategory.push_back(category);
		otherPay ++;
	}}
}

void Record::saveExit()
{
	ofstream outfile("Figure.txt",ios::app);
	int i;
	for (i = 1;i < ExpCategory.size(); i ++)
		outfile << ExpCategory[i] << " ";
	outfile << "_ ";
	for (i = 1;i < PayCategory.size(); i ++)
		outfile << PayCategory[i] << " ";
}
